package com.example.sonone.util;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * Created by Clanner on 2017/5/10.
 */
public class ExcelUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExcelUtil.class);

    // 高可用单例 ,volatile禁止指令重排
    private static volatile ExcelUtil instance;

    private ExcelUtil() {

    }

    public static ExcelUtil getInstance() {
        if (instance == null) {
            synchronized (ExcelUtil.class) {
                if (instance == null) {
                    instance = new ExcelUtil();
                }
            }
        }
        return instance;
    }


    /**
     * 数据转成excel
     *
     * @param dataList   需要转换的数据
     * @param sheetName  生成的excel表名
     * @param columnName 每一列的名字(key)
     * @param mergeRow   需合并的行数
     * @return
     */
    public void dataToExcel(String desc, List<Map<String, String>> dataList, String sheetName, List<String> columnName, List<Integer> mergeRow, HttpServletResponse servletResponse) {

        int columnNum = columnName.size();
        Workbook workbook = new HSSFWorkbook();
        //创建第一页，并命名
        Sheet sheet = workbook.createSheet(sheetName);

        sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, columnName.size() - 1));//合并单元格 参数1：起始行 参数2：终止行 参数3：起始列 参数4：终止列
        //设置列宽度 从第二行开始
        for (int i = 0; i < columnNum; i++) {
            sheet.setColumnWidth(i, 20 * 256);
        }


        // 创建三种单元格格式 (标题+字体+样式)
        CellStyle cellStyleTitle = workbook.createCellStyle();
        CellStyle cellStyleColuName = workbook.createCellStyle();
        CellStyle cellStyleData = workbook.createCellStyle();

        //第一种单元格样式 用于标题
        cellStyleTitle.setAlignment(HorizontalAlignment.CENTER_SELECTION);//水平居中
        cellStyleTitle.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中

        //第二种单元格样式 用于列名
        cellStyleColuName.setAlignment(HorizontalAlignment.CENTER_SELECTION);//水平居中
        cellStyleColuName.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中

        //第三种单元格样式 用于数据
        cellStyleData.setAlignment(HorizontalAlignment.CENTER_SELECTION);//水平居中
        cellStyleData.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中

        // 创建三种种字体  (标题+字体+样式)
        Font fTitle = workbook.createFont();
        Font fcoluName = workbook.createFont();
        Font fdata = workbook.createFont();

        //创建第一种字体样式(用于标题)
        fTitle.setFontHeightInPoints((short) 26);
        fTitle.setColor(IndexedColors.BLACK.getIndex());
        fTitle.setBold(true);//加粗 700

        // 创建第二种字体样式（用于列名）
        fcoluName.setFontHeightInPoints((short) 18);
        fcoluName.setColor(IndexedColors.BLACK.getIndex());
        fcoluName.setBold(true);

        // 创建第三种字体样式（用于数据）
        fdata.setFontHeightInPoints((short) 14);
        fdata.setColor(IndexedColors.BLACK.getIndex());
        fdata.setBold(false);//不加粗 400

        //创建第一行 用于标题
        Row rowTitle = sheet.createRow(0);  //参数是行的值
        rowTitle.setHeightInPoints(28);
        Cell cellTitle = rowTitle.createCell(0); //参数是列的值 第一行创第一列
        cellTitle.setCellValue(desc);
        cellTitle.setCellStyle(cellStyleTitle);

        //创建第二行 用于列名
        Row rowColuName = sheet.createRow(1);
        rowColuName.setHeightInPoints(22);
        for (int i = 0; i < columnNum; i++) {
            Cell cell = rowColuName.createCell(i);
            cell.setCellValue(columnName.get(i));
            //赋值单元格 样式 (列名) 在赋值之前设置
            cell.setCellStyle(cellStyleColuName);
        }
        //创建剩下行数 赋值数据
        int rowNum = dataList.size();
        for (int j = 1; j <= rowNum; j++) {
            Row r = sheet.createRow(j + 1);//因为已经有了两行，从第三行开始
            for (int k = 0; k < columnNum; k++) {
                Cell cell = r.createCell(k);
                //赋值单元格 样式 (字体) 在赋值之前设置
                cell.setCellStyle(cellStyleData);
                String data = dataList.get(j - 1).get(columnName.get(k));
                cell.setCellValue(data == null ? "-" : data);
            }
        }

        //合并 从第三行 开始 第一列 重复的数据
        int row = 2;
        for (Integer i : mergeRow) {
            //合并单元格 参数1：起始行 参数2：终止行 参数3：起始列 参数4：终止列
            sheet.addMergedRegion(new CellRangeAddress(row, row + i - 1, 0, 0));
            row += i;
        }

        // 设置response参数，可以打开下载页面
        try {
            servletResponse.reset();
            //设置请求头
            servletResponse.setHeader("Access-Control-Allow-Origin", "*");
            servletResponse.setContentType("application/vnd.ms-excel;charset=utf-8");
            servletResponse.setHeader("Content-Disposition", "attachment;filename=" + new String((desc + ".xls").getBytes(), "iso-8859-1"));
            ServletOutputStream out = servletResponse.getOutputStream();
            //io流下载
            workbook.setSheetName(0, "列表");
            workbook.write(out);
        } catch (IOException e) {
            LOGGER.info("导出ExcelUtils方法异常");
            e.printStackTrace();
        }
    }

    public void dataToExcel2(String desc, List<Map<String, String>> dataList, String sheetName, List<String> columnName, String month, HttpServletResponse servletResponse) {

        int columnNum = columnName.size();
        Workbook workbook = new HSSFWorkbook();
        //创建第一页，并命名
        Sheet sheet = workbook.createSheet(sheetName);

        sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, columnName.size() - 1));//合并单元格 参数1：起始行 参数2：终止行 参数3：起始列 参数4：终止列
        sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, columnName.size() - 1));//合并 第二行 用于月份

        //设置列宽度
        for (int i = 0; i < columnNum; i++) {
            sheet.setColumnWidth(i, 20 * 256);
        }

        // 创建三种种字体  (标题+列名字)
        Font fTitle = workbook.createFont();
        Font fcoluName = workbook.createFont();
        Font fdata = workbook.createFont();

        //创建第一种字体样式(用于标题)
        fTitle.setFontHeightInPoints((short) 14);
        fTitle.setColor(IndexedColors.BLACK.getIndex());
        fTitle.setBold(true);//加粗 700

        // 创建第二种字体样式（用于列名）
        fcoluName.setFontHeightInPoints((short) 12);
        fcoluName.setColor(IndexedColors.BLACK.getIndex());
        fcoluName.setBold(false);

        // 创建第三种字体样式（用于数据）
        fdata.setFontHeightInPoints((short) 10);
        fdata.setColor(IndexedColors.BLACK.getIndex());
        fdata.setBold(false);//不加粗 400


        // 创建四种单元格格式 (标题+字体+样式+月份)
        CellStyle cellStyleTitle = workbook.createCellStyle();
        CellStyle cellStyleMonth = workbook.createCellStyle();
        CellStyle cellStyleColuName = workbook.createCellStyle();
        CellStyle cellStyleData = workbook.createCellStyle();

        //第一种单元格样式 用于标题
        cellStyleTitle.setAlignment(HorizontalAlignment.CENTER_SELECTION);//水平居中
        cellStyleTitle.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中
        cellStyleTitle.setFont(fTitle);                             // 设置字体

        //第二种单元格样式 用于月份
        cellStyleMonth.setAlignment(HorizontalAlignment.RIGHT);       // 靠右
        cellStyleMonth.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中

        //第三种单元格样式 用于列名
        cellStyleColuName.setAlignment(HorizontalAlignment.CENTER_SELECTION);//水平居中
        cellStyleColuName.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中
        cellStyleColuName.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); // 设置颜色
        cellStyleColuName.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        cellStyleColuName.setFont(fcoluName);

        //第四种单元格样式 用于数据
        cellStyleData.setAlignment(HorizontalAlignment.CENTER_SELECTION);//水平居中
        cellStyleData.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中
        cellStyleData.setFont(fdata);


        //创建第一行 用于标题
        Row rowTitle = sheet.createRow(0);  //参数是行的值
        rowTitle.setHeightInPoints(30);
        Cell cellTitle = rowTitle.createCell(0); //参数是列的值 第一行创第一列
        cellTitle.setCellValue(desc);           // 标题名
        cellTitle.setCellStyle(cellStyleTitle);

        //创建第二行 统计月份：yyyyMM
        Row rowMonth = sheet.createRow(1);
        rowMonth.setHeightInPoints(22);
        Cell cellMonth = rowMonth.createCell(0);
        cellMonth.setCellValue("统计月份：" + month);
        cellMonth.setCellStyle(cellStyleMonth);

        //创建第三行 用于列名
        Row rowColuName = sheet.createRow(2);
        rowColuName.setHeightInPoints(22);
        for (int i = 0; i < columnNum; i++) {
            Cell cell = rowColuName.createCell(i);
            cell.setCellValue(columnName.get(i));
            //赋值单元格 样式 (列名) 在赋值之前设置
            cell.setCellStyle(cellStyleColuName);
        }

        //创建剩下行数 赋值数据
        int rowNum = dataList.size();
        for (int j = 1; j <= rowNum; j++) {
            Row r = sheet.createRow(j + 2);//因为已经有了三行，从第四行开始
            for (int k = 0; k < columnNum; k++) {
                Cell cell = r.createCell(k);
                //赋值单元格 样式 (字体) 在赋值之前设置
                cell.setCellStyle(cellStyleData);
                String data =  dataList.get(j - 1).get(columnName.get(k));
                cell.setCellValue(data == null ? "-" : data);
            }
        }


        // 设置response参数，可以打开下载页面
        try {
            servletResponse.reset();
            //设置请求头
            servletResponse.setHeader("Access-Control-Allow-Origin", "*");
            servletResponse.setContentType("application/vnd.ms-excel;charset=utf-8");
            servletResponse.setHeader("Content-Disposition", "attachment;filename=" + new String((desc + ".xlsx").getBytes(), "iso-8859-1"));
            ServletOutputStream out = servletResponse.getOutputStream();
            //io流下载
            workbook.write(out);
        } catch (IOException e) {
            LOGGER.info("导出ExcelUtils方法异常");
            e.printStackTrace();
        }
    }


}